package com.gzhryc.net_marketing.cloud.account.services;

import com.gzhryc.common.IDTools;
import com.gzhryc.common.NumberTools;
import com.gzhryc.common.StringTools;
import com.gzhryc.common.exceptions.LogicException;
import com.gzhryc.common.logging.Logger;
import com.gzhryc.jdbc.Conditions;
import com.gzhryc.jdbc.JdbcSession;
import com.gzhryc.jdbc.MultiDBTools;
import com.gzhryc.net_marketing.cloud.MarketConstants;
import com.gzhryc.net_marketing.cloud.account.dao.CloudPayAccountDao;
import com.gzhryc.net_marketing.cloud.account.dao.db.CloudPayAccount;
import com.gzhryc.net_marketing.cloud.account.dao.db.CloudPayAccountDepositOrder;
import com.gzhryc.net_marketing.cloud.account.dao.db.CloudPayAccountOperateRecord;
import com.gzhryc.net_marketing.cloud.account.dao.enums.CloudPayAccountEnum;
import com.gzhryc.net_marketing.cloud.account.dao.enums.CloudPayAccountOperateRecordEnum;
import com.gzhryc.net_marketing.cloud.account.services.dto.CloudPayAccountSearch;
import com.gzhryc.net_marketing.cloud.business.dao.db.MarketProjectApp;
import com.gzhryc.net_marketing.cloud.business.dao.db.MarketSupplier;
import com.gzhryc.net_marketing.cloud.business.services.MarketProjectAppService;
import com.gzhryc.net_marketing.cloud.business.services.MarketSupplierService;
import com.gzhryc.system.dao.db.Manager;

import java.sql.SQLException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class CloudPayAccountService {

    static Logger log = Logger.getLogger(CloudPayAccountService.class);

    public static CloudPayAccountService self() {
        return MultiDBTools.getService(MarketConstants.JDBC_KEY,CloudPayAccountService.class, true);
    }

    CloudPayAccountDao dao;

    public CloudPayAccountService(String jdbcKey) {
        this.dao = new CloudPayAccountDao(jdbcKey);
    }

    public List<CloudPayAccount> findJoinBySearch(CloudPayAccountSearch search, Integer pageNo, Integer pageLimit){
        Conditions conditions = dao.buildConditions(search);
        try {
            return dao.findJoinByCondition(conditions,pageNo,pageLimit);
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        }
        return null;
    }

    public Long countJoinBySearch(CloudPayAccountSearch search){
        Conditions conditions = dao.buildConditions(search);
        try {
            return dao.countJoin(conditions);
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        }
        return 0L;
    }
    
    public CloudPayAccount getJoinByVisitToken(Long id,String visitToken){
        if(id != null && StringTools.isNotBlank(visitToken)) {
            Conditions conditions = new Conditions(CloudPayAccount.class);
            conditions.and().is("id",id);
            conditions.and().is("visitToken",visitToken);
            try {
                return dao.getJoin(conditions);
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
        return null;
    }

    public CloudPayAccount getByPayToken(Long id,String payToken){
        if(id != null && StringTools.isNotBlank(payToken)) {
            Conditions conditions = new Conditions(CloudPayAccount.class);
            conditions.and().is("id",id);
            conditions.and().is("payToken",payToken);
            try {
                return dao.get(conditions);
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
        return null;
    }

    public CloudPayAccount getById(Long id){
        try {
            return dao.getById(id);
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        }
        return null;
    }
    
    public CloudPayAccount getJoinById(Long id){
        try {
            return dao.getJoinById(id);
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        }
        return null;
    }

    public synchronized boolean add(CloudPayAccount cloudPayAccount) throws LogicException {
        String id = IDTools.getRandomNumberStr(3) + IDTools.getTimestampMinuteID();
        cloudPayAccount.setId(Long.valueOf(id));
        cloudPayAccount.setVisitToken(IDTools.getUUID());
        cloudPayAccount.setPayToken(IDTools.getUUID());
        cloudPayAccount.setCreateDate(new Date());
        cloudPayAccount.setState(CloudPayAccountEnum.State.Enable.index());

        try {
            return dao.insert(cloudPayAccount) > 0;
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        }
        return false;
    }

    public boolean updateNotNull(CloudPayAccount cloudPayAccount) throws LogicException {
        CloudPayAccount temp = getById(cloudPayAccount.getId());
        if(temp == null){
            throw new LogicException("账号不存在");
        }

        Conditions conditions = new Conditions();
        conditions.and().is("id",cloudPayAccount.getId());

        Map<String,Object> data = new HashMap<>();
        data.put("visitToken",cloudPayAccount.getVisitToken());
        data.put("payToken",cloudPayAccount.getPayToken());
        data.put("payNotifyUrl",cloudPayAccount.getPayNotifyUrl());
        data.put("wxpayAppId",cloudPayAccount.getWxpayAppId());
        data.put("alipayAppId",cloudPayAccount.getAlipayAppId());

        try {
            return dao.update(data,conditions) > 0;
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        }
        return false;
    }

    public boolean recharge(CloudPayAccountDepositOrder depositOrder) throws LogicException {
        CloudPayAccount temp = getById(depositOrder.getAccountId());
        if(temp == null){
            throw new LogicException("账号不存在");
        }
        JdbcSession.begin();
        try {
            Conditions conditions = new Conditions(CloudPayAccount.class);
            conditions.and().is("id",temp.getId());
            conditions.and().is("money",temp.getMoney());

            CloudPayAccount updateEntity = new CloudPayAccount();
            updateEntity.setMoney(temp.getMoney() + depositOrder.getReceiptMoney());
            updateEntity.setUpdateMoneyDate(new Date());

            if(dao.updateNotNull(updateEntity,conditions) > 0){
                CloudPayAccountOperateRecord record = new CloudPayAccountOperateRecord();
                record.setAccountId(depositOrder.getAccountId());
                record.setMoneyType(CloudPayAccountOperateRecordEnum.MoneyType.DepositMoney.index());
                record.setType(CloudPayAccountOperateRecordEnum.Type.Increase.index());
                record.setMoney(depositOrder.getReceiptMoney());
                record.setOperatorType(CloudPayAccountOperateRecordEnum.OperatorType.Client.getIndex());
                record.setOperatorName(depositOrder.getPayerId());
                record.setOperateNote(depositOrder.getTitle() + "(订单："+depositOrder.getTradeNo()+")");

                if(CloudPayAccountOperateRecordService.self().add(record)) {
                    JdbcSession.commit();
                    return true;
                }
            }
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        } finally {
            JdbcSession.end();
        }
        return false;
    }

    /**
     * 人工充值
     * @param id
     * @param money
     * @param reason
     * @return
     * @throws LogicException
     */
    public boolean artificialRecharge(Long id, Double money, String reason, Manager manager)throws LogicException {
        if(money < 1 || money > 30000 ){
            throw new LogicException("充值金额必须1-30000元以内");
        }
        CloudPayAccount temp = getById(id);
        if(temp == null){
            throw new LogicException("账号不存在");
        }
        if("admin".equals(manager.getLoginName())){
            throw new LogicException("超级管理员不允许充值操作");
        }
        if(StringTools.isBlank(manager.getPhone())){
            throw new LogicException("充值操作的管理员必须有手机号");
        }
        Integer increaseMoney = NumberTools.changeMoney(money);
        JdbcSession.begin();
        try {
            Conditions conditions = new Conditions(CloudPayAccount.class);
            conditions.and().is("id",id);
            conditions.and().is("money",temp.getMoney());

            CloudPayAccount updateEntity = new CloudPayAccount();
            updateEntity.setMoney(temp.getMoney() + increaseMoney);
            updateEntity.setUpdateMoneyDate(new Date());

            if(dao.updateNotNull(updateEntity,conditions) > 0){
                CloudPayAccountOperateRecord record = new CloudPayAccountOperateRecord();
                record.setAccountId(id);
                record.setMoneyType(CloudPayAccountOperateRecordEnum.MoneyType.DepositMoney.index());
                record.setType(CloudPayAccountOperateRecordEnum.Type.Increase.index());
                record.setMoney(increaseMoney);
                record.setOperatorType(CloudPayAccountOperateRecordEnum.OperatorType.Manager.getIndex());
                record.setOperatorName(manager.getName() + "("+manager.getPhone()+")");
                record.setOperateNote(reason);

                if(CloudPayAccountOperateRecordService.self().add(record)) {
                    JdbcSession.commit();
                    return true;
                }
            }
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        } finally {
            JdbcSession.end();
        }

        return false;
    }

    public boolean reduceMoney(CloudPayAccount payAccount, Integer money, String operatorName,String reason)throws LogicException {
        if(payAccount != null && money != null && StringTools.isNotBlank(reason)){
            Conditions conditions = new Conditions(CloudPayAccount.class);
            conditions.and().is("id",payAccount.getId());
            conditions.and().is("money",payAccount.getMoney());

            Integer tempMoney = payAccount.getMoney() - money;
            if(tempMoney < 0){
                throw new LogicException("账号资金不足");
            }
            CloudPayAccount updateEntity = new CloudPayAccount();
            updateEntity.setMoney(tempMoney);
            updateEntity.setUpdateMoneyDate(new Date());

            JdbcSession.begin();
            try {
                if(dao.updateNotNull(updateEntity,conditions) > 0){
                    CloudPayAccountOperateRecord record = new CloudPayAccountOperateRecord();
                    record.setAccountId(payAccount.getId());
                    record.setMoneyType(CloudPayAccountOperateRecordEnum.MoneyType.DepositMoney.index());
                    record.setType(CloudPayAccountOperateRecordEnum.Type.Reduce.index());
                    record.setMoney(money);
                    record.setOperatorType(CloudPayAccountOperateRecordEnum.OperatorType.System.getIndex());
                    record.setOperatorName(operatorName);
                    record.setOperateNote(reason);

                    if(CloudPayAccountOperateRecordService.self().add(record)) {
                        JdbcSession.commit();
                        return true;
                    }
                }
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            } finally {
                JdbcSession.end();
            }
        }
        return false;
    }

    public boolean incomeFreezeMoney(CloudPayAccount payAccount, Integer money, String operatorName,String reason)throws LogicException {
        if(payAccount != null && money != null && StringTools.isNotBlank(reason)){
            Conditions conditions = new Conditions(CloudPayAccount.class);
            conditions.and().is("id",payAccount.getId());
            conditions.and().is("freezeMoney",payAccount.getFreezeMoney());

            Integer tempMoney = payAccount.getFreezeMoney() + money;

            CloudPayAccount updateEntity = new CloudPayAccount();
            updateEntity.setFreezeMoney(tempMoney);
            updateEntity.setUpdateFreezeMoneyDate(new Date());

            JdbcSession.begin();
            try {
                if(dao.updateNotNull(updateEntity,conditions) > 0){
                    CloudPayAccountOperateRecord record = new CloudPayAccountOperateRecord();
                    record.setAccountId(payAccount.getId());
                    record.setMoneyType(CloudPayAccountOperateRecordEnum.MoneyType.FreezeMoney.index());
                    record.setType(CloudPayAccountOperateRecordEnum.Type.Income.index());
                    record.setMoney(money);
                    record.setOperatorType(CloudPayAccountOperateRecordEnum.OperatorType.System.getIndex());
                    record.setOperatorName(operatorName);
                    record.setOperateNote(reason);

                    if(CloudPayAccountOperateRecordService.self().add(record)) {
                        JdbcSession.commit();
                        return true;
                    }
                }
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            } finally {
                JdbcSession.end();
            }
        }
        return false;
    }

    public boolean reduceFreezeMoney(CloudPayAccount payAccount, Integer money,Integer operatorType,String operatorName,String reason)throws LogicException {
        if(payAccount != null && money != null && StringTools.isNotBlank(reason)){
            Conditions conditions = new Conditions(CloudPayAccount.class);
            conditions.and().is("id",payAccount.getId());
            conditions.and().is("freezeMoney",payAccount.getMoney());

            Integer tempMoney = payAccount.getFreezeMoney() - money;
            if(tempMoney < 0){
                throw new LogicException("账号资金不足");
            }
            CloudPayAccount updateEntity = new CloudPayAccount();
            updateEntity.setFreezeMoney(tempMoney);
            updateEntity.setUpdateMoneyDate(new Date());

            JdbcSession.begin();
            try {
                if(dao.updateNotNull(updateEntity,conditions) > 0){
                    CloudPayAccountOperateRecord record = new CloudPayAccountOperateRecord();
                    record.setAccountId(payAccount.getId());
                    record.setMoneyType(CloudPayAccountOperateRecordEnum.MoneyType.DepositMoney.index());
                    record.setType(CloudPayAccountOperateRecordEnum.Type.Reduce.index());
                    record.setMoney(money);
                    record.setOperatorType(operatorType);
                    record.setOperatorName(operatorName);
                    record.setOperateNote(reason);

                    if(CloudPayAccountOperateRecordService.self().add(record)) {
                        JdbcSession.commit();
                        return true;
                    }
                }
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            } finally {
                JdbcSession.end();
            }
        }
        return false;
    }

    /**
     * 解冻金额
     * @param payAccount
     * @param money
     * @param operatorName
     * @param reason
     * @return
     * @throws LogicException
     */
    public boolean unfreezeMoney(CloudPayAccount payAccount, Integer money, Integer operatorType,String operatorName,String reason)throws LogicException {
        if(payAccount != null && money != null && StringTools.isNotBlank(reason)){
            Conditions conditions = new Conditions(CloudPayAccount.class);
            conditions.and().is("id",payAccount.getId());
            conditions.and().is("freezeMoney",payAccount.getFreezeMoney());
            conditions.and().is("money",payAccount.getMoney());

            Integer tempMoney = payAccount.getFreezeMoney() - money;
            if(tempMoney < 0){
                throw new LogicException("账号冻结金额不足");
            }
            Integer temp2Money = payAccount.getMoney() + money;

            CloudPayAccount updateEntity = new CloudPayAccount();
            updateEntity.setFreezeMoney(tempMoney);
            updateEntity.setMoney(temp2Money);
            updateEntity.setUpdateFreezeMoneyDate(new Date());
            updateEntity.setUpdateMoneyDate(new Date());

            JdbcSession.begin();
            try {
                if(dao.updateNotNull(updateEntity,conditions) > 0){
                    CloudPayAccountOperateRecord record = new CloudPayAccountOperateRecord();
                    record.setAccountId(payAccount.getId());
                    record.setMoneyType(CloudPayAccountOperateRecordEnum.MoneyType.unfreezeMoney.index());
                    record.setType(CloudPayAccountOperateRecordEnum.Type.Thaw.index());
                    record.setMoney(money);
                    record.setOperatorType(operatorType);
                    record.setOperatorName(operatorName);
                    record.setOperateNote(reason);

                    if(CloudPayAccountOperateRecordService.self().add(record)) {
                        JdbcSession.commit();
                        return true;
                    }
                }
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            } finally {
                JdbcSession.end();
            }
        }
        return false;
    }

    public boolean faceDeleteById(Long id) throws LogicException {
        JdbcSession.begin();
        try {
            if (dao.deleteById(id) > 0) {
                if (CloudPayAccountOperateRecordService.self().deleteByAccountId(id)) {
                    JdbcSession.commit();
                    return true;
                }
            }
        } catch (SQLException e) {
            log.error(e.getMessage(), e);
        } finally {
            JdbcSession.end();
        }
        return false;
    }

    public boolean deleteById(Long id) throws LogicException {
        CloudPayAccount temp = getById(id);
        if(temp == null){
            throw new LogicException("账号不存在");
        }
        if(temp.getMoney() > 0 || temp.getFreezeMoney() > 0){
            throw new LogicException("账号还存在金额，不允许删除");
        }
        
        if(CloudPayAccountEnum.Type.MarketApp.index().equals(temp.getType())) {
        	MarketProjectApp projectApp = MarketProjectAppService.self().getByAccountId(id);
        	if(projectApp != null) {
        		throw new LogicException("请先删除关联的" + CloudPayAccountEnum.Type.MarketApp.note());
        	}
        }else if(CloudPayAccountEnum.Type.Supplier.index().equals(temp.getType())) {
        	MarketSupplier marketSupplier = MarketSupplierService.self().getByAccountId(id);
        	if(marketSupplier != null) {
        		throw new LogicException("请先删除关联的" + CloudPayAccountEnum.Type.Supplier.note());
        	}
        }
        
        JdbcSession.begin();
        try {
            if(dao.deleteById(id) > 0){
                if(CloudPayAccountOperateRecordService.self().deleteByAccountId(id)) {
                    JdbcSession.commit();
                    return true;
                }
            }
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        } finally {
            JdbcSession.end();
        }
        return false;
    }
}
